﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevComponents.DotNetBar.Controls;
using System.Drawing;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.ComponentModel;
using System.Globalization;
using DevComponents.DotNetBar;
using DevComponents.DotNetBar.Rendering;
using System.Drawing.Drawing2D;

namespace KP_CommonLibrary.KP_CommonControls
{
    public class MultiColumnComboBox : ComboBoxEx, ISupportInitialize
    {
        public event EventHandler TextNotInSource;
        private bool _AutoComplete = true;
        private bool _AutoDropdown;
        private Color _BackColorEven = Color.White;
        private Color _BackColorOdd = Color.White;
        private string _ColumnNameString = "";
        private int _ColumnWidthDefault = 75;
        private string _ColumnWidthString = "";
        private string _ColumnTextlengh = "";

        private int _LinkedColumnIndex;
        private TextBox _LinkedTextBox;
        private int _TotalWidth = 0;
        private int _ValueMemberColumnIndex = 0;

        private Collection<string> _ColumnNames = new Collection<string>();
        private Collection<int> _ColumnWidths = new Collection<int>();

        public MultiColumnComboBox()
            : base()
        {
            DrawMode = DrawMode.OwnerDrawVariable;
            base.BackColor = KP_UIConfig.EditBackColor;
            base.ForeColor = KP_UIConfig.EditForeColor;
            // If all of your boxes will be RightToLeft, uncomment 
            // the following line to make RTL the default.
            //RightToLeft = RightToLeft.Yes;

            // Remove the Context Menu to disable pasting 
            ContextMenu = new ContextMenu();
            Leave += new EventHandler(MultiColumnComboBox_Leave);
        }

        void MultiColumnComboBox_Leave(object sender, EventArgs e)
        {
            if (SelectedIndex < 0 && Text.Length > 0)
            {
                if (TextNotInSource != null)
                    TextNotInSource(this, new TextNotInSourceArgs(Text));
            }
        }

        public event System.EventHandler OpenSearchForm;
        [DefaultValue(true)]
        public bool AutoComplete
        {
            get
            {
                return _AutoComplete;
            }
            set
            {
                _AutoComplete = value;
            }
        }

        public bool AutoDropdown
        {
            get
            {
                return _AutoDropdown;
            }
            set
            {
                _AutoDropdown = value;
            }
        }

        public Color BackColorEven
        {
            get
            {
                return _BackColorEven;
            }
            set
            {
                _BackColorEven = value;
            }
        }

        public Color BackColorOdd
        {
            get
            {
                return _BackColorOdd;
            }
            set
            {
                _BackColorOdd = value;
            }
        }

        public Collection<string> ColumnNameCollection
        {
            get
            {
                return _ColumnNames;
            }
        }

        public string ColumnNames
        {
            get
            {
                return _ColumnNameString;
            }

            set
            {
                // If the column string is blank, leave it blank.
                // The default width will be used for all columns.
                if (!Convert.ToBoolean(value.Trim().Length))
                {
                    _ColumnNameString = "";
                }
                else if (value != null)
                {
                    char[] delimiterChars = { ',', ';', ':' };
                    string[] columnNames = value.Split(delimiterChars);

                    if (!DesignMode)
                    {
                        _ColumnNames.Clear();
                    }

                    // After splitting the string into an array, iterate
                    // through the strings and check that they're all valid.
                    foreach (string s in columnNames)
                    {
                        // Does it have length?
                        if (Convert.ToBoolean(s.Trim().Length))
                        {
                            if (!DesignMode)
                            {
                                _ColumnNames.Add(s.Trim());
                            }
                        }
                        else // The value is blank
                        {
                            throw new NotSupportedException("Column names can not be blank.");
                        }
                    }
                    _ColumnNameString = value;
                }
            }
        }

        public Collection<int> ColumnWidthCollection
        {
            get
            {
                return _ColumnWidths;
            }
        }

        public int ColumnWidthDefault
        {
            get
            {
                return _ColumnWidthDefault;
            }
            set
            {
                _ColumnWidthDefault = value;
            }
        }
        public string ColumnTextlengh
        {
            get { return _ColumnTextlengh; }
            set { _ColumnTextlengh = value; }
        }
        public string ColumnWidths
        {
            get
            {
                return _ColumnWidthString;
            }

            set
            {
                // If the column string is blank, leave it blank.
                // The default width will be used for all columns.
                if (!Convert.ToBoolean(value.Trim().Length))
                {
                    _ColumnWidthString = "";
                }
                else if (value != null)
                {
                    char[] delimiterChars = { ',', ';', ':' };
                    string[] columnWidths = value.Split(delimiterChars);
                    string invalidValue = "";
                    int invalidIndex = -1;
                    int idx = 1;
                    int intValue;

                    // After splitting the string into an array, iterate
                    // through the strings and check that they're all integers
                    // or blanks
                    foreach (string s in columnWidths)
                    {
                        // If it has length, test if it's an integer
                        if (Convert.ToBoolean(s.Trim().Length))
                        {
                            // It's not an integer. Flag the offending value.
                            if (!int.TryParse(s, out intValue))
                            {
                                invalidIndex = idx;
                                invalidValue = s;
                            }
                            else // The value was okay. Increment the item index.
                            {
                                idx++;
                            }
                        }
                        else // The value is a space. Use the default width.
                        {
                            idx++;
                        }
                    }

                    // If an invalid value was found, raise an exception.
                    if (invalidIndex > -1)
                    {
                        string errMsg;

                        errMsg = "Invalid column width '" + invalidValue + "' located at column " + invalidIndex.ToString();
                        throw new ArgumentOutOfRangeException(errMsg);
                    }
                    else // The string is fine
                    {
                        _ColumnWidthString = value;

                        // Only set the values of the collections at runtime.
                        // Setting them at design time doesn't accomplish 
                        // anything and causes errors since the collections 
                        // don't exist at design time.
                        if (!DesignMode)
                        {
                            _ColumnWidths.Clear();
                            foreach (string s in columnWidths)
                            {
                                // Initialize a column width to an integer
                                if (Convert.ToBoolean(s.Trim().Length))
                                {
                                    _ColumnWidths.Add(Convert.ToInt32(s));
                                }
                                else // Initialize the column to the default
                                {
                                    _ColumnWidths.Add(_ColumnWidthDefault);
                                }
                            }

                            // If the column is bound to data, set the column widths
                            // for any columns that aren't explicitly set by the 
                            // string value entered by the programmer
                            if (DataManager != null)
                            {
                                InitializeColumns();
                            }
                        }
                    }
                }
            }
        }


        public new DrawMode DrawMode
        {
            get
            {
                return base.DrawMode;
            }
            set
            {
                if (value != DrawMode.OwnerDrawVariable)
                {
                    //throw new NotSupportedException("Needs to be DrawMode.OwnerDrawVariable");
                }
                base.DrawMode = value;
            }
        }

        public new ComboBoxStyle DropDownStyle
        {
            get
            {
                return base.DropDownStyle;
            }
            set
            {
                if (value != ComboBoxStyle.DropDown)
                {
                    throw new NotSupportedException("ComboBoxStyle.DropDown is the only supported style");
                }
                base.DropDownStyle = value;
            }
        }

        public int LinkedColumnIndex
        {
            get
            {
                return _LinkedColumnIndex;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException("A column index can not be negative");
                }
                _LinkedColumnIndex = value;
            }
        }

        public TextBox LinkedTextBox
        {
            get
            {
                return _LinkedTextBox;
            }
            set
            {
                _LinkedTextBox = value;

                if (_LinkedTextBox != null)
                {
                    // Set any default properties of the Linked Textbox here
                    _LinkedTextBox.ReadOnly = true;
                    _LinkedTextBox.TabStop = false;
                }
            }
        }

        public int TotalWidth
        {
            get
            {
                return _TotalWidth;
            }
        }

        protected override void OnDataSourceChanged(EventArgs e)
        {
            base.OnDataSourceChanged(e);

            InitializeColumns();
            SelectedIndex = -1;
            Invalidate();
        }
        protected override void OnLeave(EventArgs e)
        {
            if (wholeSearchExist)
            {
                // Text = "";
                SelectedIndex = -1;
                SelectedValue = foundKey;
                ///Invalidate();
            }
            base.OnLeave(e);



        }

        protected override void DrawObjectItem(DrawItemEventArgs e)
        {
            Graphics g = e.Graphics;
            string text = GetItemText(this.Items[e.Index]);
            Color textColor = Color.Empty;
            Office2007ButtonItemStateColorTable ct = null;

            if (BarFunctions.IsOffice2007Style(this.Style))
            {
                Office2007ButtonItemColorTable bct = ((Office2007Renderer)GlobalManager.Renderer).ColorTable.ButtonItemColors[0];
                if ((e.State & DrawItemState.Selected) != 0 || (e.State & DrawItemState.HotLight) != 0)
                    ct = bct.MouseOver;
                else if ((e.State & DrawItemState.Disabled) != 0 || !this.Enabled)
                    ct = bct.Disabled;
                else
                    ct = bct.Default;

                //if (ct != null)
                //    textColor = ct.Text;
                if ((e.State & DrawItemState.Disabled) != 0 || !this.Enabled)
                    textColor = DisabledForeColor.IsEmpty ? SystemColors.ControlDark : DisabledForeColor;
                else
                    textColor = this.ForeColor;
                if ((e.State & DrawItemState.HotLight) != 0 || (e.State & DrawItemState.Selected) != 0)
                {
                    Rectangle r = e.Bounds;
                    r.Width--;
                    r.Height--;
                    //                    Office2007ButtonItemPainter.PaintBackground(g, ct, r, RoundRectangleShapeDescriptor.RoundCorner2);
                    PaintBackground(g, ct, r, RoundRectangleShapeDescriptor.RoundCorner2);
                }
                else
                    e.DrawBackground();
            }
            else
            {
                e.DrawBackground();

                if ((e.State & DrawItemState.HotLight) != 0 || (e.State & DrawItemState.Selected) != 0)
                {
                    g.FillRectangle(SystemBrushes.Highlight, e.Bounds);
                    textColor = SystemColors.HighlightText;
                }
                else if ((e.State & DrawItemState.Disabled) != 0 || (e.State & DrawItemState.Grayed) != 0)
                    textColor = DisabledForeColor.IsEmpty ? SystemColors.ControlDark : DisabledForeColor;
                else
                    textColor = SystemColors.ControlText;
            }

            if ((e.State & DrawItemState.Focus) != 0)
                DrawFocusRectangle(e);
            Rectangle rText = e.Bounds;

            if ((e.State & DrawItemState.ComboBoxEdit) == DrawItemState.ComboBoxEdit)
            {
                //rText.Inflate(-1, 0);

            }
            else if (BarFunctions.IsOffice2007Style(this.Style))
                rText.Inflate(-3, 0);
            else
                rText.Inflate(-2, 0);

            Rectangle boundsRect = e.Bounds;
            int lastRight = 0;
            #region Test
            /*---*/
            using (Pen linePen = new Pen(SystemColors.GrayText))
            {
                //using (SolidBrush brush = new SolidBrush(brushForeColor))
                {
                    if (!Convert.ToBoolean(_ColumnNames.Count))
                    {
                        TextDrawing.DrawString(g, text, this.Font, textColor, rText, eTextFormat.Default | eTextFormat.NoClipping | eTextFormat.NoPrefix);
                    }
                    else
                    {
                        // If the ComboBox is displaying a RightToLeft language, draw it this way.
                        if (RightToLeft.Equals(RightToLeft.Yes))
                        {
                            // Define a StringFormat object to make the string display RTL.
                            StringFormat rtl = new StringFormat();
                            rtl.Alignment = StringAlignment.Near;
                            rtl.FormatFlags = StringFormatFlags.DirectionRightToLeft;

                            // Draw the strings in reverse order from high column index to zero column index.
                            for (int colIndex = _ColumnNames.Count - 1; colIndex >= 0; colIndex--)
                            {
                                if (Convert.ToBoolean(_ColumnWidths[colIndex]))
                                {
                                    string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));

                                    boundsRect.X = lastRight;
                                    boundsRect.Width = (int)_ColumnWidths[colIndex];
                                    lastRight = boundsRect.Right;
                                    boundsRect.X = boundsRect.X - 3;
                                    boundsRect.Width = boundsRect.Width - 3;
                                    // Draw the string with the RTL object.
                                    // e.Graphics.DrawString(item, Font, brush, boundsRect, rtl);
                                    TextDrawing.DrawString(g, item, this.Font, textColor, boundsRect, eTextFormat.Default | eTextFormat.NoClipping | eTextFormat.NoPrefix);
                                    if (colIndex > 0)
                                    {
                                        e.Graphics.DrawLine(linePen, lastRight, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
                                    }
                                }
                            }
                        }
                        // If the ComboBox is displaying a LeftToRight language, draw it this way.
                        else
                        {
                            // Display the strings in ascending order from zero to the highest column.
                            for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
                            {
                                if (Convert.ToBoolean(_ColumnWidths[colIndex]))
                                {
                                    string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));

                                    boundsRect.X = lastRight;
                                    boundsRect.Width = (int)_ColumnWidths[colIndex];
                                    lastRight = boundsRect.Right;
                                    boundsRect.X = boundsRect.X + 3;
                                    boundsRect.Width = boundsRect.Width - 3;
                                    //e.Graphics.DrawString(item, Font, brush, boundsRect);
                                    TextDrawing.DrawString(g, item, this.Font, textColor, boundsRect, eTextFormat.Default | eTextFormat.NoClipping | eTextFormat.NoPrefix);
                                    if (colIndex < _ColumnNames.Count - 1)
                                    {
                                        e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            /*--*/
            #endregion Test


            //  TextDrawing.DrawString(g, text, this.Font, textColor, rText, eTextFormat.Default | eTextFormat.NoClipping | eTextFormat.NoPrefix);
        }
        public static void PaintBackground(Graphics g, Office2007ButtonItemStateColorTable stateColors, Rectangle r, IShapeDescriptor shape)
        {
            PaintBackground(g, stateColors, r, shape, false);
        }

        public static void PaintBackground(Graphics g, Office2007ButtonItemStateColorTable stateColors, Rectangle r, IShapeDescriptor shape, bool isDefault)
        {
            PaintBackground(g, stateColors, r, shape, isDefault, true);
        }
        public static void PaintBackground(Graphics g, Office2007ButtonItemStateColorTable stateColors, Rectangle r, IShapeDescriptor shape, bool isDefault, bool paintBorder)
        {
            float topSplit = .35f;
            float bottomSplit = .65f;
            if (!shape.CanDrawShape(r)) return;

            if (stateColors != null)
            {
                Rectangle fillRectangle = r;
                Rectangle backRect = new Rectangle(fillRectangle.X, fillRectangle.Y, fillRectangle.Width, (int)(fillRectangle.Height * topSplit));
                if (!stateColors.OuterBorder.IsEmpty && paintBorder)
                    fillRectangle.Width--;
                GraphicsPath backPath = shape.GetShape(fillRectangle);
                if (stateColors.Background != null)
                {
                    if (backPath != null)
                    {
                        using (LinearGradientBrush lb = new LinearGradientBrush(fillRectangle, stateColors.Background.Start, stateColors.Background.End, stateColors.Background.GradientAngle))
                        {
                            g.FillPath(lb, backPath);
                        }
                        backPath.Dispose();
                    }
                }
                else
                {
                    if (backPath != null)
                    {
                        if (stateColors.TopBackground.End.IsEmpty && stateColors.BottomBackground.End.IsEmpty)
                        {
                            if (stateColors.TopBackground.Start == stateColors.BottomBackground.Start)
                                using (SolidBrush lb = new SolidBrush(stateColors.TopBackground.Start))
                                    g.FillPath(lb, backPath);
                            else
                            {
                                using (LinearGradientBrush lb = new LinearGradientBrush(fillRectangle, stateColors.TopBackground.Start, stateColors.BottomBackground.Start, stateColors.TopBackground.GradientAngle))
                                {
                                    g.FillPath(lb, backPath);
                                }
                            }
                        }
                        else
                        {
                            using (LinearGradientBrush lb = new LinearGradientBrush(fillRectangle, stateColors.TopBackground.Start, stateColors.BottomBackground.End, stateColors.TopBackground.GradientAngle))
                            {
                                ColorBlend cb = new ColorBlend(4);
                                cb.Colors = new Color[] { stateColors.TopBackground.Start, stateColors.TopBackground.End, stateColors.BottomBackground.Start, stateColors.BottomBackground.End };
                                cb.Positions = new float[] { 0, topSplit, topSplit, 1f };
                                lb.InterpolationColors = cb;
                                g.FillPath(lb, backPath);
                            }
                        }
                        backPath.Dispose();
                    }

                    if (!stateColors.TopBackgroundHighlight.IsEmpty)
                    {
                        Rectangle ellipse = new Rectangle(fillRectangle.X, fillRectangle.Y, fillRectangle.Width, fillRectangle.Height);
                        GraphicsPath path = new GraphicsPath();
                        path.AddEllipse(ellipse);
                        PathGradientBrush brush = new PathGradientBrush(path);
                        brush.CenterColor = stateColors.TopBackgroundHighlight.Start;
                        brush.SurroundColors = new Color[] { stateColors.TopBackgroundHighlight.End };
                        brush.CenterPoint = new PointF(ellipse.X + ellipse.Width / 2, fillRectangle.Bottom);
                        Blend blend = new Blend();
                        blend.Factors = new float[] { 0f, .5f, 1f };
                        blend.Positions = new float[] { .0f, .4f, 1f };
                        brush.Blend = blend;

                        g.FillRectangle(brush, backRect);
                        brush.Dispose();
                        path.Dispose();
                    }

                    // Draw Bottom part
                    int bottomHeight = (int)(fillRectangle.Height * bottomSplit);
                    backRect = new Rectangle(fillRectangle.X, fillRectangle.Y + backRect.Height, fillRectangle.Width, fillRectangle.Height - backRect.Height);

                    if (!stateColors.BottomBackgroundHighlight.IsEmpty)
                    {
                        Rectangle ellipse = new Rectangle(fillRectangle.X, fillRectangle.Y + bottomHeight - 2, fillRectangle.Width, fillRectangle.Height + 4);
                        GraphicsPath path = new GraphicsPath();
                        path.AddEllipse(ellipse);
                        PathGradientBrush brush = new PathGradientBrush(path);
                        brush.CenterColor = stateColors.BottomBackgroundHighlight.Start;
                        brush.SurroundColors = new Color[] { stateColors.BottomBackgroundHighlight.End };
                        brush.CenterPoint = new PointF(ellipse.X + ellipse.Width / 2, fillRectangle.Bottom);
                        Blend blend = new Blend();
                        blend.Factors = new float[] { 0f, .5f, .6f };
                        blend.Positions = new float[] { .0f, .4f, 1f };
                        brush.Blend = blend;

                        g.FillRectangle(brush, backRect);
                        brush.Dispose();
                        path.Dispose();
                    }
                }

                if (paintBorder)
                {
                    SmoothingMode sm = g.SmoothingMode;
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    // Draw Border
                    if (!stateColors.OuterBorder.IsEmpty)
                    {
                        Rectangle br = r;
                        br.Width--;
                        br.Height--;
                        GraphicsPath path = shape.GetShape(br);
                        if (path != null)
                        {
                            DisplayHelp.DrawGradientPath(g, path, r, stateColors.OuterBorder, 1);
                            path.Dispose();
                        }
                        //if (cornerSize > 1)
                        //    DisplayHelp.DrawRoundGradientRectangle(g, r, stateColors.OuterBorder, 1, cornerSize);
                        //else
                        //    DisplayHelp.DrawGradientRectangle(g, r, stateColors.OuterBorder, 1);

                        if (isDefault)
                        {
                            Color clr = Color.FromArgb(128, stateColors.OuterBorder.Start);
                            r.Inflate(-1, -1);
                            DisplayHelp.DrawRectangle(g, clr, r);
                            r.Inflate(-1, -1);
                            DisplayHelp.DrawRectangle(g, clr, r);
                        }
                    }
                    if (!isDefault && !stateColors.InnerBorder.IsEmpty)
                    {
                        Rectangle innerRect = r;
                        innerRect.Inflate(-1, -1);
                        innerRect.Width--;
                        innerRect.Height--;
                        using (GraphicsPath path = shape.GetInnerShape(innerRect, 1))
                            DisplayHelp.DrawGradientPath(g, path, innerRect, stateColors.InnerBorder, 1);
                        //cornerSize--;
                        //if (cornerSize > 1)
                        //    DisplayHelp.DrawRoundGradientRectangle(g, innerRect, stateColors.InnerBorder, 1, cornerSize);
                        //else
                        //    DisplayHelp.DrawGradientRectangle(g, innerRect, stateColors.InnerBorder, 1);
                    }

                    g.SmoothingMode = sm;
                }
            }
        }

        private void DrawFocusRectangle(DrawItemEventArgs e)
        {
            if (FocusCuesEnabled && ((e.State & DrawItemState.Focus) == DrawItemState.Focus) && ((e.State & DrawItemState.NoFocusRect) != DrawItemState.NoFocusRect))
            {
                Rectangle r = e.Bounds;
                //r.Width--;
                //r.Height--;
                ControlPaint.DrawFocusRectangle(e.Graphics, r, e.ForeColor, e.BackColor);
            }
        }
        //protected override void OnDrawItem(DrawItemEventArgs e)
        //{
        //    return;

        //    base.OnDrawItem(e);

        //    if (DesignMode)
        //        return;

        //    e.DrawBackground();

        //    Rectangle boundsRect = e.Bounds;
        //    int lastRight = 0;

        //    Color brushForeColor;
        //    if ((e.State & DrawItemState.Selected) == 0)
        //    {
        //        // Item is not selected. Use BackColorOdd & BackColorEven
        //        Color backColor;
        //        backColor = Convert.ToBoolean(e.Index % 2) ? _BackColorOdd : _BackColorEven;
        //        using (SolidBrush brushBackColor = new SolidBrush(backColor))
        //        {
        //            e.Graphics.FillRectangle(brushBackColor, e.Bounds);
        //        }
        //        brushForeColor = Color.Black;
        //    }
        //    else
        //    {
        //        // Item is selected. Use ForeColor = White
        //        brushForeColor = Color.White;
        //    }

        //    using (Pen linePen = new Pen(SystemColors.GrayText))
        //    {
        //        using (SolidBrush brush = new SolidBrush(brushForeColor))
        //        {
        //            if (!Convert.ToBoolean(_ColumnNames.Count))
        //            {
        //                e.Graphics.DrawString(Convert.ToString(Items[e.Index]), Font, brush, boundsRect);
        //            }
        //            else
        //            {
        //                // If the ComboBox is displaying a RightToLeft language, draw it this way.
        //                if (RightToLeft.Equals(RightToLeft.Yes))
        //                {
        //                    // Define a StringFormat object to make the string display RTL.
        //                    StringFormat rtl = new StringFormat();
        //                    rtl.Alignment = StringAlignment.Near;
        //                    rtl.FormatFlags = StringFormatFlags.DirectionRightToLeft;

        //                    // Draw the strings in reverse order from high column index to zero column index.
        //                    for (int colIndex = _ColumnNames.Count - 1; colIndex >= 0; colIndex--)
        //                    {
        //                        if (Convert.ToBoolean(_ColumnWidths[colIndex]))
        //                        {
        //                            string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));

        //                            boundsRect.X = lastRight;
        //                            boundsRect.Width = (int)_ColumnWidths[colIndex];
        //                            lastRight = boundsRect.Right;

        //                            // Draw the string with the RTL object.
        //                            e.Graphics.DrawString(item, Font, brush, boundsRect, rtl);

        //                            if (colIndex > 0)
        //                            {
        //                                e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
        //                            }
        //                        }
        //                    }
        //                }
        //                // If the ComboBox is displaying a LeftToRight language, draw it this way.
        //                else
        //                {
        //                    // Display the strings in ascending order from zero to the highest column.
        //                    for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
        //                    {
        //                        if (Convert.ToBoolean(_ColumnWidths[colIndex]))
        //                        {
        //                            string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));

        //                            boundsRect.X = lastRight;
        //                            boundsRect.Width = (int)_ColumnWidths[colIndex];
        //                            lastRight = boundsRect.Right;
        //                            e.Graphics.DrawString(item, Font, brush, boundsRect);

        //                            if (colIndex < _ColumnNames.Count - 1)
        //                            {
        //                                e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
        //                            }
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //    }

        //    e.DrawFocusRectangle();
        //}

        protected override void OnDropDown(EventArgs e)
        {
            base.OnDropDown(e);

            if (_TotalWidth > 0)
            {
                if (Items.Count > MaxDropDownItems)
                {
                    // The vertical scrollbar is present. Add its width to the total.
                    // If you don't then RightToLeft languages will have a few characters obscured.
                    this.DropDownWidth = _TotalWidth + SystemInformation.VerticalScrollBarWidth;
                }
                else
                {
                    this.DropDownWidth = _TotalWidth;
                }
            }
        }
        protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
            {
                string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));
                SizeF sizeF = e.Graphics.MeasureString(item, Font);
                _ColumnWidths[colIndex] = Math.Max(_ColumnWidths[colIndex], (int)sizeF.Width);
            }

            CalculateTotalWidth();

            e.ItemWidth = _TotalWidth;
            base.OnMeasureItem(e);

        }

        private void CalculateTotalWidth()
        {
            _TotalWidth = 0;
            foreach (int node in _ColumnWidths)
                _TotalWidth += node;
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            // Use the Delete or Escape Key to blank out the ComboBox and
            // allow the user to type in a new value
            //SelectedIndex = -1;
            if ((e.KeyCode == Keys.Delete) ||
                (e.KeyCode == Keys.Escape))
            {
                SelectedIndex = -1;
                Text = "";
                if (_LinkedTextBox != null)
                {
                    _LinkedTextBox.Text = "";
                }
            }
            else if (e.KeyCode == Keys.F3)
            {
                // Fire the OpenSearchForm Event
                if (OpenSearchForm != null)
                {
                    OpenSearchForm(this, System.EventArgs.Empty);
                }
            }
        }

        // Some of the code for OnKeyPress was derived from some VB.NET code  
        // posted by Laurent Muller as a suggested improvement for another control.
        // http://www.codeproject.com/vb/net/autocomplete_combobox.asp?df=100&forumid=3716&select=579095#xx579095xx
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            int idx = -1, prevousIdx = SelectedIndex;

            string toFind = "";
            wholeSearchExist = false;
            foundKey = null;


            Debug.WriteLine("Key press " + e.KeyChar);
            DroppedDown = _AutoDropdown;
            if (!Char.IsControl(e.KeyChar))
            {
                if (_AutoComplete)
                {
                    toFind = Text.Substring(0, SelectionStart) + e.KeyChar;
                    Debug.WriteLine("Autocomplete for " + toFind);
                    idx = FindStringExact(toFind);

                    if (idx == -1)
                    {
                        // An exact match for the whole string was not found
                        // Find a substring instead.
                        Debug.WriteLine("No FindStringExact , try FindString");
                        idx = FindString(toFind, -1);
                    }
                    else
                    {
                        // An exact match was found. Close the dropdown.
                        DroppedDown = false;
                    }

                    if (idx < 0)
                        SearchItem(toFind);
                }
                else // AutoComplete = false. Treat it like a DropDownList by finding the
                // KeyChar that was struck starting from the current index
                {
                    toFind = e.KeyChar.ToString();
                    idx = FindString(toFind, SelectedIndex);
                }
            }

            // Do no allow the user to backspace over characters. Treat it like
            // a left arrow instead. The user must not be allowed to change the 
            // value in the ComboBox. 
            if ((e.KeyChar == (char)(Keys.Back)) &&  // A Backspace Key is hit
                (_AutoComplete) &&                   // AutoComplete = true
                (Convert.ToBoolean(SelectionStart))) // And the SelectionStart is positive
            {
                // Find a substring that is one character less the the current selection.
                // This mimicks moving back one space with an arrow key. This substring should
                // always exist since we don't allow invalid selections to be typed. If you're
                // on the 3rd character of a valid code, then the first two characters have to 
                // be valid. Moving back to them and finding the 1st occurrence should never fail.
                Debug.WriteLine("Backspace state");
                Text = Text.Substring(0, SelectionStart - 1);
                toFind = Text;
                idx = FindString(toFind);
                Debug.WriteLine("Search for " + toFind + " Index:" + idx.ToString());

                if (idx < 0)
                    SearchItem(toFind);

            }


            if (idx >= 0)
            {
                if (idx != prevousIdx)
                    SelectedIndex = idx;
                else
                {
                    SelectedIndex = -1;
                    SelectedIndex = idx;
                }
                SelectionStart = toFind.Length;
                SelectionLength = Text.Length - SelectionStart;
            }
            if (idx < 0)
            {
                //string text = Text;
                SelectedIndex = -1;
                //Text = text;
                Text = toFind;
                if (Text.Length > 0)
                {
                    SelectionStart = toFind.Length;
                    SelectionLength = Text.Length - SelectionStart;
                }
            }
            e.Handled = true;
            //DroppedDown = true;

        }

        protected override void OnSelectedValueChanged(EventArgs e)
        {
            base.OnSelectedValueChanged(e); //Added after version 1.3 on 01/31/2008

            if (_LinkedTextBox != null)
            {
                if (_LinkedColumnIndex < _ColumnNames.Count)
                {
                    _LinkedTextBox.Text = Convert.ToString(FilterItemOnProperty(SelectedItem, _ColumnNames[_LinkedColumnIndex]));
                }
            }
        }

        protected override void OnValueMemberChanged(EventArgs e)
        {
            base.OnValueMemberChanged(e);

            InitializeValueMemberColumn();
        }

        /// <summary>
        /// Nếu _ColumnNameString  is null thi thêm toàn bộ các thuộc tính có trogn datasoure vào các cột hiển thị
        /// Tính Toán TotalWith của một item;
        /// </summary>
        private void InitializeColumns()
        {
            if (!Convert.ToBoolean(_ColumnNameString.Length) && DataManager != null)
            {
                PropertyDescriptorCollection propertyDescriptorCollection = DataManager.GetItemProperties();

                _TotalWidth = 0;
                _ColumnNames.Clear();

                for (int colIndex = 0; colIndex < propertyDescriptorCollection.Count; colIndex++)
                {
                    _ColumnNames.Add(propertyDescriptorCollection[colIndex].Name);

                    // If the index is greater than the collection of explicitly
                    // set column widths, set any additional columns to the default
                    if (colIndex >= _ColumnWidths.Count)
                    {
                        _ColumnWidths.Add(_ColumnWidthDefault);
                    }
                    _TotalWidth += _ColumnWidths[colIndex];
                }
            }
            else if (_ColumnNameString.Length > 0)
            {
                _TotalWidth = 0;

                for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
                {
                    // If the index is greater than the collection of explicitly
                    // set column widths, set any additional columns to the default
                    if (colIndex >= _ColumnWidths.Count)
                    {
                        _ColumnWidths.Add(_ColumnWidthDefault);
                    }
                    _TotalWidth += _ColumnWidths[colIndex];
                }

            }

            // Check to see if the programmer is trying to display a column
            // in the linked textbox that is greater than the columns in the 
            // ComboBox. I handle this error by resetting it to zero.
            if (_LinkedColumnIndex >= _ColumnNames.Count)
            {
                _LinkedColumnIndex = 0; // Or replace this with an OutOfBounds Exception
            }
        }

        private void InitializeValueMemberColumn()
        {
            int colIndex = 0;
            foreach (String columnName in _ColumnNames)
            {
                if (String.Compare(columnName, ValueMember, true, CultureInfo.CurrentUICulture) == 0)
                {
                    _ValueMemberColumnIndex = colIndex;
                    break;
                }
                colIndex++;
            }
        }

        bool wholeSearchExist = false;
        object foundKey = "";
        int SearchItem(string s)
        {
            foundKey = "";
            wholeSearchExist = false;
            Debug.Write("SearchItem");
            if (DataSource is DataTable || DataSource is DataView)
            {
                DataTable tblData = DataSource as DataTable;
                if (tblData == null)
                    tblData = (DataSource as DataView).Table;
                foreach (string col in ColumnNameCollection)
                {
                    if (col == DisplayMember)
                        continue;
                    string selected = col + " LIKE '" + s + "%'";
                    if (tblData.Columns[col].DataType != typeof(string))
                    {
                        selected = "Convert(" + col + ",'System.String')" + " LIKE '" + s + "%'";
                    }

                    DataRow[] exists = tblData.Select(selected);
                    if (exists.Length > 0)
                    {
                        foundKey = exists[0][ValueMember];
                        Text = exists[0][col].ToString();
                        SelectionStart = s.Length;
                        SelectionLength = Text.Length - SelectionStart;
                        wholeSearchExist = true;
                        return 1;
                    }
                    else
                        continue;

                }
            }
            else
            {
                for (int i = 0; i < Items.Count; i++)
                {
                    for (int j = 0; j < _ColumnNames.Count; j++)
                    {
                        string temp = FilterItemOnProperty(Items[i], _ColumnNames[j]).ToString();
                        if (temp.StartsWith(s, StringComparison.CurrentCultureIgnoreCase))
                        {
                            foundKey = FilterItemOnProperty(Items[i], ValueMember);
                            Text = temp;
                            SelectionStart = s.Length;
                            SelectionLength = Text.Length - SelectionStart;
                            wholeSearchExist = true;
                            break;
                        }
                    }
                }
            }
            return -1;
        }


        public class TextNotInSourceArgs : EventArgs
        {
            private string text;
            public string Text
            {
                get { return text; }
            }
            public TextNotInSourceArgs(string s)
                : base()
            {
                text = s;
            }
        }

        #region ISupportInitialize Members
        bool isIniting = false;
        public void BeginInit()
        {
            isIniting = true;
        }

        public void EndInit()
        {
            isIniting = false;
            if (DesignMode)
            {
                //MessageBox.Show("DesignMode");
                return;
            }
            InitializeColumns();
        }

        #endregion
    }
}
